duangsuse::Echo
https://github.com/Enaium/LrcToSrt/tree/master/LrcToSrt #CSharp 的转换工具 https://github.com/caroltc/lrc2srt python 后端网页处理 https://github.com/URenko/lrc2srt https://github.com/SIDmao/lrc2srt 这个是 shellscript (awk/sed) 的 https://github.com/alicesister1/lrc2srt C++…
他们怎么就不能向 pandoc 学习一下…… 弄那么多 bcc2srt bcc2ass ass2lrc 限定了输入输出,还在子程序里限制输入必须是 file 什么的而不是抽象出一个 readline iterator…… 闹了半天不仅兼容性垃圾,写那么多代码连互化都做不到,草死了
Forwarded from duangsuse Throws
GitHub
不如来看看隔壁的 extract-subtitles? · Issue #7 · HenryLulu/video-to-text-ocr-demo
https://github.com/duangsuse-valid-projects/extract-subtitles 这个是我改的,原作者比较学院派,没有那些 fixed rate 什么的,主要是 absdiff(m1, m2) 和 scipy.signal.argrelextrema 提取关键帧(key frame) 也就是说没有这种算法: for frame_no in range...
https://github.com/notepad-plus-plus/notepad-plus-plus/commit/bf2cd8e05abf5ca6c93cdc8011e0023292aeedb8#commitcomment-38574535 #GitHub #China
I see your point. However, since the author and main maintainer of
I see your point. However, since the author and main maintainer of
taiwaneseMandarin.xml is a Taiwanese but not a Chinese nor a Hongkongners, I think it's fair to call it Taiwan Mandarin. OTOH, language/culture/region naming is just a conventional way, while people understand what it does mean, non-conventional way can be used.GitHub
Changes localization file name "chinese.xml" to "taiwaneseMandarin.xml" · notepad-plus-plus/notepad-plus-plus@bf2cd8e
Saying Taiwan is part of China is like saying Java is part of JavaScript.
https://www.mono-project.com/docs/gui/gtksharp/widgets/treeview-tutorial/ #Csharp #Gtk
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/ #Windows #gui
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/ #Windows #gui
Docs
Xamarin.Forms CollectionView - Xamarin
The CollectionView is a flexible and performant view for presenting lists of data using different layout specifications.
LrcToSrtGtk.zip
36.7 KB
看到某个 .NET WPF 4.0 XAML UI 写的项目想移植下到 GTK# ,发现不行,弃了。 Gtk# 也是牛逼,居然没发现有 SelectionChangedEvent ,而且有 TreeView 无 ListView ,GUI designer 也是不知道怎么 access 已经命好名的 widget ,唉
SRT 格式:
item, elementIn, not
Seq, Repeat, JoinBy, SurroundBy
数字应该还好读吧... 我写个
其实我就是想把
time int:int:int,intLRC 格式:
(int
timespan --> time
!nl*
nl nl)*
CommonPart🤔应该怎么样呢……
'[' int ':' int '.' int ']' white? anyChar* nl?
'<' int ':' int '.' int '>' white? ![<\[\]]*
Tag
'[' ![0-9]+ ':' anyChar* ']'
File (Tag|CommonPart)* CommonPart*
item, elementIn, not
Seq, Repeat, JoinBy, SurroundBy
数字应该还好读吧... 我写个
class NumberUnit:好了…… 还是咸鱼点吧,懒得再用 Python 重写现如今的 parserkt 了……
def __init__(self, unit):
self.unit = unit
def _digits(self, n):
if n < self.unit: yield n; return
accum = n
while accum > self.unit:
(accum, k) = divmod(accum, self.unit)
yield k
if int(accum) != 0: yield accum
def convFrom(self, n): return reversed(list(self._digits(n)))
def convBack(self, ks):
accum = 0
for k in ks: accum = accum*self.unit + k
return accum
其实我就是想把
[mm:ss.xx] a <mm:ss.xx> b给弄成
[Part("norm", mm:ss.xx, "a"), Part("word", mm:ss.xx, "b")] ,然后 zipWithNext() 处理啊…… 结果没有能直接完成两种工作的库
duangsuse::Echo
SRT 格式: time int:int:int,int (int timespan --> time !nl* nl nl)* LRC 格式: CommonPart '[' int ':' int '.' int ']' white? anyChar* nl? '<' int ':' int '.' int '>' white? ![<\[\]]* Tag '[' ![0-9]+ ':' anyChar* ']' File (Tag|CommonPart)* CommonPart* 🤔应该怎么样呢………
from functools import partial
partial(print, ..., 1),虽然后来我发现即便 lambda 这个很长但也可以用,emmmdef require(value, p, msg):
if not p(value): raise ValueError(f"{msg}: {value}")
def zipWithNext(xs):
require(xs, lambda it: len(it) > 2, "must >2")
for i in range(1, len(xs)):
yield (xs[i-1], xs[i])
def zipTakeWhile(xs, predicate):
for (a, b) in zipWithNext(xs):
if not predicate(a, b): break
yield a; yield b 嗯…… 我们想要合并的歌词其实就是
(note join by distance < cfg.d) join by distance >= cfg.d 所以只需要
while True:
print(next(linez))
except StopIteration: pass 就可以啦…… 到底还是有点麻烦
我好可怜,为什么他们不弄好这种工具给我…… 明明是很常见的 Vocaloid 歌词,只不过是给 UTAU 的而已啊
开源的概念本身没有什么问题,尽管能让人看的“成绩”并不少,但它需要得到支持的地方也很多。
开源的概念本身没有什么问题,尽管能让人看的“成绩”并不少,但它需要得到支持的地方也很多。
https://github.com/RikkaApps/SaveCopy #Android #code
build.gradle
app/src/main/java/app/rikka/savecopy
SaveActivity.java
太长不看,会有大致的梗概
build.gradle
apply plugin: "com.android.application"
android {
defaultConfig { compileSdkVersion 14
applicationId "app.rikka.savecopy"
versionCode 1; versionName "1.0"
minSdkVersion 14; targetSdkVersion 29
}
signingConfigs { sign }
buildTypes {
debug {
signingConfig signingConfigs.sign
}
release {
signingConfig signingConfigs.sign
minifyEnabled true; proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')
shrinkResources true
}
}
buildFeatures { buildConfig = false }
lintOptions.checkReleaseBuilds = false
dependenciesInfo.includeInApk = false
}
android.applicationVariants.all { variant ->
variant.outputs.all { it.outputFileName = "save-copy-v${versionName}.apk" }
}
dependencies {
implementation "androidx.annotation:annotation:1.1.0"
}
apply from: rootProject.file("signing.gradle") app/src/main/java/app/rikka/savecopy
SaveActivity.java
import android.app.Activity;SaveService.java
import android.content.Intent;
import android.os.Bundle;
public class SaveActivity extends Activity {
@Override protected void onCreate(Bundle state) {
super.onCreate(state);
if (!getIntent().getAction() == Intent.ACTION_VIEW) return;
Intent passIntent = new Intent(getIntent());
passIntent.setClassName(this, SaveService.class.getName());
startService(passIntent);
finish();
}
}
太长不看,会有大致的梗概
GitHub
GitHub - RikkaApps/SaveCopy: Simple Android app, handle ACTION_VIEW, ACTION_SEND, ACTION_SEND_MULTIPLE, save a copy of the file.…
Simple Android app, handle ACTION_VIEW, ACTION_SEND, ACTION_SEND_MULTIPLE, save a copy of the file. For bad apps which only allow users to open files. - RikkaApps/SaveCopy
总的来说,代码太多挑重点看。先从 doSave 的实际保存逻辑开始。
当然还是不得不先从入口逻辑的 registry 看。
https://github.com/RikkaApps/SaveCopy/blob/435ddc702f79956e5d89aaf1050cafbd7e277df6/app/src/main/java/app/rikka/savecopy/SaveService.java#L149
总的来说是从 content solver 弄出带失败 fallback 的
啊,上面的函数不对,给个默认
注意下面的代码和上面的并行依赖于
上一步要产生
我先吐嘈吐嘈,以前王垠说要用
先来看看这个数据的 reference 在哪。
最后才是关键部分,用到
的时候并没有人觉得这该被包装成类似 Observer 的形式 😂。
其中
当然还是不得不先从入口逻辑的 registry 看。
public class SaveService extends IntentService {
public SaveService() { super("save-thread"); }
public SaveService(String name) { this(); }
protected void onHandleIntent(Intent intent) { onSave(intent); }
}
private void onSave(Intent intent) {
try { doSave(intent); }
catch (IOException | InterruptedException e) { e.printStackTrace(); }
}
private void doSave(Intent intent) throws IOException, InterruptedException https://github.com/RikkaApps/SaveCopy/blob/435ddc702f79956e5d89aaf1050cafbd7e277df6/app/src/main/java/app/rikka/savecopy/SaveService.java#L149
Uri data = intent.getData();
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(data, null, null, null, null);
String displayName = "unknown-" + System.currentTimeMillis();
long totalSize = -1;
if (cursor != null && cursor.moveToFirst()) {
displayName = mapDefaultNon(-1, displayName, cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME), it -> it.getString(displayNameIndex));
totalSize = mapDefaultNon(-1, totalSize, cursor.getColumnIndex(OpenableColumns.SIZE), it -> it.getLong(sizeIndex));
cursor.close();
}
private <T> T takeNonOr(T value, T except, T default) {
return (value.equals(except))? default : value;
} //我也没有更好更接近 zero-cost 的方法了,用 Kotlin? 可是那个配置 proguard 更麻烦
//用工具方法?或者用 lambda? 总的来说是从 content solver 弄出带失败 fallback 的
String displayName; long totalSize; 啊,上面的函数不对,给个默认
mapDefaultNon 实现: (不得不说是很拗口,因为我拼写错了两次,但总的来看是值得的…… 虽然肯定不是唯一可行也绝对不该是最终方案)import java.util.function.Function;
private <T, R> R mapDefaultNon(T except, R default_value, T value, Function<T, R> transform) {
return (value.equals(except))? default_value : transform(value);
} 注意下面的代码和上面的并行依赖于
Uri data = intent.getData(); 引用。InputStream ins = cr.openInputStream(data); if (ins == null) return; //在 Kotlin 有等价 ?: return 形式来看看下一个生成 ContentValues 的逻辑
import MediaStore.MediaColumns //canonical type name?
ContentValues values = new ContentValues();
if (Build.VERSION.SDK_INT >= 29) {
values.put(MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
values.put(MediaColumns.IS_PENDING, true);
} else {
values.put(MediaColumns.DATA, Environment.getExternalStorageDirectory()+File.separator+Environment.DIRECTORY_DOWNLOADS+File.separator+displayName);
}
注,其实直接用 new File(dir, name) 而不是 File.seprator 拼接也很好啦values.put(MediaColumns.DISPLAY_NAME, displayName);
Uri target = EXTERNAL_CONTENT_URI;
}
其中private final Uri EXTERNAL_CONTENT_URI = (Build.VERSION.SDK_INT >= 29)? MediaStore.Downloads.EXTERNAL_CONTENT_URI : MediaStore.Files.getContentUri("external"); 上一步要产生
Uri target; ContentValues values; ,它们的数据依赖都是零散的,来看下一步Uri uri = cr.insert(target, values); if (uri == null) return; 我先吐嘈吐嘈,以前王垠说要用
Optional<T> 解决 null 问题,我真不觉得那会很好用,Kotlin 的设计多棒啊。int id = uri.toString().hashCode(); //顺便说一句,拿 hashCode() 不需要先 toString() 吧,既然是数据类的话先来看看这个数据的 reference 在哪。
scheduleNotification(id, builder); //仅被用于创建通知最后才是关键部分,用到
ParcelFileDescriptor , OutputStream 。ParcelFileDescriptor fd = getContentResolver().openFileDescriptor(uri, "rw"); // 其实本来可以加个 takeOrThrow 完成Function内非局部返回的,但是想想还是算了 if (fd == null) return; OutputStream outs = new ParcelFileDescriptor.AutoCloseOutputStream(fd);接下来就是经典部分了,为了方便大家了解日常在你们手机里运行并且被重复无数遍的代码是什么样子,我直接粘贴好了(没
long writeSize = 0;也是蛮有意思的,其实只要是字节流操作,这样
byte[] buffer = new byte[8192];
for (int n; (n = ins.read(buffer)) != (-1);) {
outs.write(0, buffer, n);
outs.flush();
writeSize += n;
onBufferWrote.accept(writeSize);
}
outs.close(); ins.close();
Log.i("Save", writeSize, totalSize);
read(buffer); wirte(0, buffer, n) 的代码总会重复无数次,被我略略视为应该少用的 (-1) 也不得不使用,没有太好的解决方案因为通用的 android SDK 包创建的时候并没有人觉得这该被包装成类似 Observer 的形式 😂。
其中
onBufferWrote 在上面定义:import java.util.function.Consumer;1000 这个常量可以抽提,但我注意到
Consumer<Long> onBufferWrote = (n_wrote) -> {
if (totalSize == (-1) ) return;
int progress = (int) ((float)n_wrote/totalSize *100);
builder.setProgress(100, progress, true);
scheduleNotification(id, builder, 1000);
};
scheduleNotification(id, builder, ...) 有4处引用,包括省略参数的2处不能直接省略GitHub
RikkaApps/SaveCopy
Simple Android app, handle ACTION_VIEW, save a copy of the file. For bad apps which only allow users to open files. - RikkaApps/SaveCopy